using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices.Protocols;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using OracleInternal.Common;

namespace OracleInternal.Network
{
	internal class LDAP : INamingAdapter
	{
		internal static string m_ID;

		private static string m_OracleContext;

		private static string m_LdapFilter;

		private static string m_orclNetDescStringAttr;

		private static string m_aliasObjectNameStringAttr;

		private static string[] m_AttributesToReturn;

		private static string CNEQUALS;

		private static string DCEQUALS;

		private static string CEQUALS;

		private static string OEQUALS;

		private static string OUEQUALS;

		private static char EQUALCHAR;

		private static char ATCHAR;

		private static char DOTCHAR;

		private static int m_PageSize;

		private static string SYNTAXERROR;

		private static string NOLDAPSERVERCONFIGURED;

		private Hashtable m_AliasesDescriptionsMap = new Hashtable(StringComparer.OrdinalIgnoreCase);

		private LdapConfig m_LdapConfig;

		private static LdapConfig s_LdapConfig;

		public string ID => m_ID;

		public Hashtable Map
		{
			get
			{
				Hashtable hashtable = new Hashtable();
				_LDAP(hashtable);
				if (hashtable.Count <= 0)
				{
					return null;
				}
				return hashtable;
			}
		}

		static LDAP()
		{
			m_ID = "LDAP";
			m_OracleContext = "cn=OracleContext";
			m_LdapFilter = "(|(objectClass=orclNetService)(objectClass=orclService)(objectClass=orclNetServiceAlias))";
			m_orclNetDescStringAttr = "orclNetDescString";
			m_aliasObjectNameStringAttr = "aliasedobjectname";
			m_AttributesToReturn = new string[2]
			{
				m_orclNetDescStringAttr,
				m_aliasObjectNameStringAttr
			};
			CNEQUALS = "cn=";
			DCEQUALS = "dc=";
			CEQUALS = "c=";
			OEQUALS = "o=";
			OUEQUALS = "ou=";
			EQUALCHAR = '=';
			ATCHAR = '@';
			DOTCHAR = '.';
			m_PageSize = 999;
			SYNTAXERROR = "Syntax error.";
			NOLDAPSERVERCONFIGURED = "No LDAP server is configured.";
			s_LdapConfig = new LdapConfig();
		}

		internal LDAP()
		{
			m_LdapConfig = s_LdapConfig;
		}

		internal LDAP(SqlNetOraConfig SNOConfig, Hashtable ObLdapHT)
		{
			m_LdapConfig = new LdapConfig((SNOConfig != null) ? SNOConfig : s_LdapConfig.SNOConfig, (ObLdapHT != null) ? ObLdapHT : s_LdapConfig.LDAPconfigParameters);
		}

		private void _LDAP(Hashtable dsMap)
		{
			LdapConnection ldapConnection = null;
			dsMap.Clear();
			if (m_LdapConfig.LdapDirectoryIdentifiers == null)
			{
				return;
			}
			List<LdapDirectoryIdentifier> ldapDirectoryIdentifiers = m_LdapConfig.LdapDirectoryIdentifiers;
			SearchRequest searchRequest = new SearchRequest(m_OracleContext + "," + m_LdapConfig.DefaultAdminContext, m_LdapFilter, SearchScope.Subtree, m_AttributesToReturn);
			PageResultRequestControl pageResultRequestControl = new PageResultRequestControl(m_PageSize);
			searchRequest.Controls.Add(pageResultRequestControl);
			for (int i = 0; i < ldapDirectoryIdentifiers.Count; i++)
			{
				try
				{
					ldapConnection = CreateLdapConnection(ldapDirectoryIdentifiers[i]);
					bool flag = false;
					while (!flag)
					{
						SearchResponse searchResponse = (SearchResponse)ldapConnection.SendRequest(searchRequest);
						DirectoryControl[] controls = searchResponse.Controls;
						foreach (DirectoryControl directoryControl in controls)
						{
							if (directoryControl is PageResultResponseControl)
							{
								pageResultRequestControl.Cookie = ((PageResultResponseControl)directoryControl).Cookie;
								break;
							}
						}
						foreach (SearchResultEntry entry in searchResponse.Entries)
						{
							string text = ExtractKey(entry.DistinguishedName);
							if (string.IsNullOrEmpty(text))
							{
								continue;
							}
							string value = Attribute2String(entry.Attributes[m_orclNetDescStringAttr]);
							if (!string.IsNullOrEmpty(value))
							{
								if (!dsMap.Contains(text))
								{
									dsMap[text] = value;
								}
								continue;
							}
							string text2 = Attribute2String(entry.Attributes[m_aliasObjectNameStringAttr]);
							if (string.IsNullOrEmpty(text2))
							{
								continue;
							}
							SearchRequest request = new SearchRequest(text2, m_LdapFilter, SearchScope.Base, m_AttributesToReturn);
							SearchResponse searchResponse2 = (SearchResponse)ldapConnection.SendRequest(request);
							if (searchResponse2.Entries.Count > 0)
							{
								value = Attribute2String(searchResponse2.Entries[0].Attributes[m_orclNetDescStringAttr]);
								if (!string.IsNullOrEmpty(value) && !dsMap.Contains(text))
								{
									dsMap[text] = value;
								}
							}
						}
						if (pageResultRequestControl.Cookie.Length == 0)
						{
							flag = true;
						}
					}
				}
				catch (Exception ex)
				{
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						_trace("exception occured  - " + ex.ToString());
					}
				}
				if (ldapConnection != null)
				{
					ldapConnection.Dispose();
					ldapConnection = null;
				}
			}
		}

		private string ExtractKey(string distinguishedName)
		{
			if (string.IsNullOrEmpty(distinguishedName))
			{
				return null;
			}
			int num = distinguishedName.IndexOf('=') + 1;
			int num2 = distinguishedName.IndexOf(',');
			if (num2 > num)
			{
				return distinguishedName.Substring(num, num2 - num);
			}
			return null;
		}

		private LdapConnection CreateLdapConnection(LdapDirectoryIdentifier ldapDirectoryId)
		{
			LdapConnection ldapConnection = new LdapConnection(ldapDirectoryId);
			ldapConnection.Timeout = new TimeSpan(0, 0, m_LdapConfig.SNOConfig.LDAPCTimeout);
			ldapConnection.AuthType = m_LdapConfig.Authtype;
			LdapSessionOptions sessionOptions = ldapConnection.SessionOptions;
			sessionOptions.ProtocolVersion = 3;
			if (m_LdapConfig.Authtype == AuthType.External || m_LdapConfig.useSSL)
			{
				sessionOptions.SecureSocketLayer = true;
				if (m_LdapConfig.Authtype == AuthType.External)
				{
					ldapConnection.ClientCertificates.AddRange(m_LdapConfig.X509Collection);
				}
				sessionOptions.VerifyServerCertificate = AnonymousVerifyServeCertificateCallback;
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace("binding to LDAP server: " + ((ldapDirectoryId.Servers.Length != 0) ? ldapDirectoryId.Servers[0] : "default LDAP server."));
			}
			ldapConnection.Bind();
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace("binded to LDAP server");
			}
			return ldapConnection;
		}

		private static string Attribute2String(DirectoryAttribute directoryAttribute)
		{
			return directoryAttribute?[0].ToString();
		}

		public static bool AnonymousVerifyServeCertificateCallback(LdapConnection ldapConn, X509Certificate serverCert)
		{
			return true;
		}

		public string Resolve(string TNSname, out ConnectionOption CO, string IN = null, string ServerIs = null)
		{
			CO = null;
			if (m_LdapConfig.LdapDirectoryIdentifiers == null)
			{
				if (ProviderConfig.m_bTraceLevelNetwork)
				{
					_trace(NOLDAPSERVERCONFIGURED);
				}
				return null;
			}
			SearchRequest searchRequest = null;
			bool flag = false;
			string text = string.Copy(TNSname);
			int num = text.IndexOf(EQUALCHAR);
			if (num > 0 && string.Compare(text.Substring(0, num + 1).Replace(" ", null), CNEQUALS, StringComparison.OrdinalIgnoreCase) == 0)
			{
				searchRequest = new SearchRequest(TNSname, m_LdapFilter, SearchScope.Base, m_AttributesToReturn);
				flag = true;
			}
			if (!flag && num < 0)
			{
				string text2 = null;
				int num2 = text.IndexOf(ATCHAR);
				int num3 = text.IndexOf(DOTCHAR);
				if (num2 < 0 && num3 < 0)
				{
					text2 = CNEQUALS + TNSname + "," + m_OracleContext;
					if (!string.IsNullOrEmpty(m_LdapConfig.DefaultAdminContext))
					{
						text2 = text2 + "," + m_LdapConfig.DefaultAdminContext;
					}
					searchRequest = new SearchRequest(text2, m_LdapFilter, SearchScope.Base, m_AttributesToReturn);
					flag = true;
				}
				else if (num2 > 0 || num3 > 0)
				{
					bool useDC = false;
					string text3 = null;
					if (num2 > 0)
					{
						useDC = true;
						text3 = text.Substring(0, num2);
						text = text.Substring(num2 + 1);
						num3 = text3.IndexOf(DOTCHAR);
						if (num3 < 0)
						{
							text2 = CNEQUALS + text3 + "," + m_OracleContext;
						}
						else if (num3 > 0)
						{
							string[] array = text3.Split(new char[1]
							{
								DOTCHAR
							});
							text2 = CNEQUALS + array[0] + "," + m_OracleContext;
							for (int i = 1; i < array.Length; i++)
							{
								if (!string.IsNullOrEmpty(array[i]))
								{
									text2 = text2 + "," + OUEQUALS + array[i];
									continue;
								}
								text2 = null;
								break;
							}
						}
					}
					else if (num2 < 0)
					{
						text3 = text.Substring(0, num3);
						if (!string.IsNullOrEmpty(text3))
						{
							text2 = CNEQUALS + text3 + "," + m_OracleContext;
						}
						text = text.Substring(num3 + 1);
					}
					if (!string.IsNullOrEmpty(text2))
					{
						if (!string.IsNullOrEmpty(text))
						{
							string text4 = null;
							try
							{
								text4 = Convert2rdns(text, useDC);
							}
							catch (Exception ex)
							{
								if (ProviderConfig.m_bTraceLevelNetwork)
								{
									_trace("exception occured while resolving " + TNSname + " - " + ex.ToString());
								}
								return null;
							}
							if (!string.IsNullOrEmpty(text4))
							{
								text2 = text2 + "," + text4;
							}
						}
						searchRequest = new SearchRequest(text2, m_LdapFilter, SearchScope.Base, m_AttributesToReturn);
						flag = true;
					}
				}
			}
			if (flag)
			{
				LdapConnection ldapConnection = null;
				List<LdapDirectoryIdentifier> ldapDirectoryIdentifiers = m_LdapConfig.LdapDirectoryIdentifiers;
				searchRequest.Aliases = DereferenceAlias.Always;
				for (int j = 0; j < ldapDirectoryIdentifiers.Count; j++)
				{
					try
					{
						ldapConnection = CreateLdapConnection(ldapDirectoryIdentifiers[j]);
						if (ProviderConfig.m_bTraceLevelNetwork)
						{
							_trace("query " + ((ldapDirectoryIdentifiers[j].Servers.Length != 0) ? ldapDirectoryIdentifiers[j].Servers[0] : "default LDAP server") + " for " + searchRequest.DistinguishedName);
						}
						SearchResponse searchResponse = (SearchResponse)ldapConnection.SendRequest(searchRequest);
						if (searchResponse.Entries.Count > 0)
						{
							string result = Attribute2String(searchResponse.Entries[0].Attributes[m_orclNetDescStringAttr]);
							if (ldapConnection != null)
							{
								ldapConnection.Dispose();
								ldapConnection = null;
							}
							return result;
						}
					}
					catch (Exception ex2)
					{
						if (ProviderConfig.m_bTraceLevelNetwork)
						{
							_trace("Exception occured - " + ex2.ToString());
						}
					}
					if (ldapConnection != null)
					{
						ldapConnection.Dispose();
						ldapConnection = null;
					}
				}
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				_trace(TNSname + " is not valid for LDAP Naming Adapter.");
			}
			return null;
		}

		private string Convert2rdns(string alias, bool useDC)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (alias.IndexOf(DOTCHAR) == 0)
			{
				throw new Exception(SYNTAXERROR);
			}
			string[] array = alias.Split(new char[1]
			{
				DOTCHAR
			});
			int num = array.Length - 1;
			int num2 = array.Length - 2;
			for (int i = 0; i < array.Length; i++)
			{
				if (string.IsNullOrEmpty(array[i]))
				{
					throw new Exception(SYNTAXERROR);
				}
				if (useDC || m_LdapConfig.DACwithDC)
				{
					stringBuilder.Append(DCEQUALS);
				}
				else if (m_LdapConfig.DACwithC && i == num)
				{
					stringBuilder.Append(CEQUALS);
				}
				else if (m_LdapConfig.DACwithC && i == num2 && m_LdapConfig.DACwithO)
				{
					stringBuilder.Append(OEQUALS);
				}
				else if (!m_LdapConfig.DACwithC && i == num && m_LdapConfig.DACwithO)
				{
					stringBuilder.Append(OEQUALS);
				}
				else
				{
					stringBuilder.Append(OUEQUALS);
				}
				stringBuilder.Append(array[i]);
				if (i < num)
				{
					stringBuilder.Append(",");
				}
			}
			return stringBuilder.ToString();
		}

		public void Refresh()
		{
		}

		private static void _trace(string msg)
		{
			string text = new StackFrame(1).GetMethod()!.Name + "(): " + msg;
			OracleInternal.Common.Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Sqlnet, OracleTraceClassName.TNSresolvedAddr, OracleTraceFuncName._trace, text);
		}
	}
}
